package com.cweb.framework.generator.gen;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.cweb.framework.base.serivce.BaseSerivce;
import com.cweb.framework.generator.GenConstant;
import com.cweb.framework.generator.gen.bean.GeneratorFile;
import com.cweb.framework.generator.gen.config.GeneratorSetting;
import com.cweb.framework.generator.tableInfo.entity.TableInfo;
import com.cweb.framework.pojo.CustomException;
import com.cweb.framework.util.ErrorEnum;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 自动生成代码
 */
@Service
public class GeneratorService extends BaseSerivce {
    private static final Log log = LogFactory.get();

    /* 配置 */
    // 作者
    public final static String SETTING_AUTHOR = "changfan";

    /**
     * 代码生成
     */
    public List<GeneratorFile> generator(TableInfo tableInfo, GeneratorSetting setting) {
        log.info("开始 - 代码生成【{}】" , tableInfo.getTableName());
        List<GeneratorFile> ret = new ArrayList<GeneratorFile>();
        // 设定值
        if(null == setting){
            setting = new GeneratorSetting();
        }
        // 取得映射值对应
        Map<String, Object> renderValue = getRenderValue(tableInfo, setting);
        // 配置引擎
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig(GeneratorUtil.SETTING_BASE_VM_PATH, TemplateConfig.ResourceMode.CLASSPATH));
        // 取得模板列表
        for (String path : GeneratorUtil.getTemplatesList(setting)) {
            // 渲染模板
            Template template = engine.getTemplate(GeneratorUtil.SETTING_BASE_VM_PATH + path);
            // 新建生成对象
            GeneratorFile generatorFile = new GeneratorFile(
                    GeneratorUtil.getFileName(path, tableInfo, setting),
                    template.render(renderValue)
            );
            ret.add(generatorFile);
            log.info("已生成文件【{}】" , generatorFile.getPath());
        }
        log.info("结束 - 代码生成【{}】" , tableInfo.getTableName());
        return ret;
    }

    /**
     * 文件输出
     */
    public void outFile(List<GeneratorFile> fileList, GeneratorSetting setting) throws CustomException {
        log.info("开始 - 代码输出【{}】" , setting.getGeneratorType());
        try {
            if ("zip".equals(setting.getGeneratorType())){
                // 输出文件打包下载
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                ZipOutputStream zip = new ZipOutputStream(outputStream);
                // 遍历文件内容
                for (GeneratorFile generatorFile : fileList){
                    // 添加到zip
                    zip.putNextEntry(new ZipEntry(generatorFile.getPath()));
                    IOUtils.write(generatorFile.getContent(), zip, GenConstant.CHARACTER_UTF8); // 输出
                    zip.closeEntry();
                }
                // 返回byte
                IOUtils.closeQuietly(zip);
                byte[] data = outputStream.toByteArray();

                // 输出
                HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
                if (null != data && "zip".equals(setting.getGeneratorType())){
                    response.reset();
                    response.setHeader("Content-Disposition", "attachment; filename=\"generator.zip\"");
                    response.addHeader("Content-Length", "" + data.length);
                    response.setContentType("application/octet-stream; charset=UTF-8");
                    IOUtils.write(data, response.getOutputStream());
                }
            }else {
                // 直接覆盖原文件
                String strDirPath = System.getProperty("user.dir");
                // 遍历文件内容
                for (GeneratorFile generatorFile : fileList){
                    File file = new File(strDirPath + GenConstant.PATH_division +  generatorFile.getPath());
                    if(file.exists() && StrUtil.isBlank(setting.getIsOverride())){
                        throw new CustomException(ErrorEnum.COMM_FILE_EXIST);
                    }else {
                        file.mkdirs();
                    }
                    FileOutputStream outFileOut = new FileOutputStream(file);
                    IOUtils.write(generatorFile.getContent(), outFileOut);
                    IOUtils.closeQuietly(outFileOut);
                }
            }
        }catch (IOException e){
            log.error(e);
            throw new CustomException(ErrorEnum.COMM_FILE_ERROR);
        }
        log.info("结束 - 代码输出【{}】" , setting.getGeneratorType());
    }


    /**
     * 生成模板设置用映射
     */
    private Map<String, Object> getRenderValue(TableInfo table, GeneratorSetting setting) {
        Map<String, Object> ret = new HashMap<String, Object>();
        String packageName = GeneratorUtil.getJavaPath(table, setting);
        // 设置
        ret.put("tableName", table.getTableName());
        ret.put("tableNameShort", table.getTableNameShort());
        ret.put("tableComment", table.getTableComment());
        ret.put("primaryKey", table.getPrimaryKey());
        ret.put("className", table.getClassName());
        ret.put("classNameUpper", table.getClassNameUpper());
        ret.put("module", setting.getModule());
        ret.put("columns", table.getColumns());
        ret.put("basePackage", packageName);
        ret.put("package", packageName);
        ret.put("author", SETTING_AUTHOR);
        return ret;
    }
}
